﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.IO;

namespace Cartography.Desktop
{
    class Cache
    {

        int size;
        ArrayList cachedTiles;
        Bitmap imgVacia;
        public string pathMapasPng;

        public void Vaciar()
        {
            imgVacia = null;
            cachedTiles = null;
            //tilesCache = null;
            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();
        }

        public Cache(string pathTiles,Bitmap noImage,int sizeCache)
        {
            //tilesCacheados = new Bitmap[MAX_TILE];
            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();
            cachedTiles = new ArrayList(sizeCache);
            this.size = sizeCache;
            pathMapasPng = pathTiles;
            imgVacia = noImage;
        }

        //busca un tile primero en el cache, si falla lo busca en el 
        //disco y lo agrega al cache, y si falla de nuevo, retorna
        //una imagen vacia
        public Bitmap buscarTile(int zoom, int fila, int columna)
        {
            Bitmap bitmap = buscarCache(zoom, fila, columna);

            //Esta en memoria
            if (bitmap != null)
            {
                return bitmap;
            }

            bitmap = buscarEnDisco(zoom, fila, columna);

            //esta en disco
            if (bitmap != null)
            {
                return bitmap;
            }
            //no esta en disco
            return imgVacia;
        }

        private Bitmap buscarCache(int zoom, int fila, int columna)
        {
            Tile encontrado = null;
            Bitmap bitmap;
            foreach (Tile t in cachedTiles)
            {
                //esta en el cache
                if (t.Zoom == zoom && t.Fila == fila && t.Columna == columna)
                {
                    encontrado = t;
                }
            }
            if (encontrado != null)
            {
                //Ya que alguien esta buscando este tile, lo muevo al 
                //final de la lista, marcandolo como el usado más recientemente
                cachedTiles.Remove(encontrado);
                cachedTiles.Add(encontrado);
                bitmap = encontrado.Imagen;
            }
            else
            {
                bitmap = null;
            }
            return bitmap;
        }

        private Bitmap buscarEnDisco(int zoom, int fila, int columna)
        {
            Bitmap bitmap;
            string nombreArchivo = pathMapasPng + "\\" + zoom + "\\" + fila + "\\" + columna+ ".png";
            if (!File.Exists(nombreArchivo))
            {
                return null;
            }
            /*FileStream stm = File.Open(nombreArchivo,FileMode.Open);
            if (stm != null)
            {
                bitmap = new Bitmap(stm);
                stm.Close();
                agregarCache(zoom, fila, columna, bitmap);                
            }*/

            else
            {
                try
                {
                    bitmap = new Bitmap(nombreArchivo);
                    agregarCache(zoom, fila, columna, bitmap);
                    //outofmemory
                }
                catch (Exception)
                {
                    bitmap = null;
                }
            }
            return bitmap;
        }

        private void agregarCache(int zoom, int fila, int columna, Bitmap bitmap)
        {

            //agregamos al final de la lista, marcandolo como el 
            //mas usado recientemente
            cachedTiles.Add(new Tile(zoom, fila, columna, bitmap));

            //borrar tiles viejos
            if (cachedTiles.Count > this.size)
            {

                //borramos el primer tile de la lista, donde esta el
                //menos usado recientemente (LRU)
                cachedTiles.RemoveAt(0);

                //por siaca
                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
            }
        }
    }
}
